package com.xdl.modules.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.beluga.core.BPay;
import com.beluga.core.model.PayModel;
import com.beluga.core.model.wechat.WxBPayOrderCloseResult;
import com.beluga.core.model.wechat.WxBPayRefundRequest;
import com.beluga.core.model.wechat.WxBPayRefundResult;
import com.beluga.core.pay.BPayChannel;
import com.beluga.core.props.WxPayProperties;
import com.beluga.core.util.DateUtil;
import com.beluga.core.util.Func;
import com.beluga.core.util.SnowflakeIdUtil;
import com.beluga.core.util.WxPayTools;
import com.beluga.notice.sms.SMSClient;
import com.beluga.notice.sms.SMSEntity;
import com.google.common.collect.Maps;
import com.xdl.configuration.BaseContextHandler;
import com.xdl.modules.constant.OrderEnum;
import com.xdl.modules.dto.WxActivityDto;
import com.xdl.modules.dto.WxOrderDto;
import com.xdl.modules.dto.WxOrderToken;
import com.xdl.modules.entity.SysAnnouncement;
import com.xdl.modules.entity.WxOrderDetail;
import com.xdl.modules.entity.WxOwnerCoupon;
import com.xdl.modules.entity.WxUserTemp;
import com.xdl.modules.mapper.WxOrderDetailMapper;
import com.xdl.modules.model.WxOrderModel;
import com.xdl.modules.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xdl.modules.util.WxWorkApi;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author iron guo
 * @since 2022-04-30
 */
@Service
@AllArgsConstructor
public class WxOrderDetailServiceImpl extends ServiceImpl<WxOrderDetailMapper, WxOrderDetail> implements WxOrderDetailService {

    private WxOwnerCouponService ownerCouponService;

    private WxUserTempService tempService;

    private BPay bPay;

    private WxActivityDetailService detailService;

    private CacheService cacheService;

    private WxPayProperties properties;

    private SMSClient smsClient;

    private SysAnnouncementService announcementService;

    private WxWorkApi wxWorkApi;

    @Override
    @Transactional
    public WxOrderToken order(WxOrderDetail order) {
        WxActivityDto act = detailService.getActById(order.getActId());
        /**
         * 保存活动订单
         */
        String orderSn = "X-" + SnowflakeIdUtil.nextId();
        order.setOrderSn(orderSn);
        WxOrderToken result = new WxOrderToken();
        Map<String, String> payinfo = Maps.newHashMap();
        if (Func.isNotEmpty(act.getNeedPay()) && act.getNeedPay()) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            /**
             * 获取预支付令牌
             */
            PayModel pay = new PayModel();
            pay.setOpenid(BaseContextHandler.getOpenId());
            pay.setOutTradeNo(orderSn);
            pay.setChannelId(BPayChannel.WECHAT_PAY.getPay());
            pay.setAmount(String.valueOf(order.getPrice()));
            pay.setCallback(properties.getCallback() + "/wx/order/callback");
            pay.setDescription(act.getTitle());
            pay.setIsSandbox(false);
            pay.setSpbillCreateIp(WxPayTools.getRealIp(request));
            payinfo = bPay.payToken(pay);
            result.setPayInfo(payinfo);
        } else {
            order.setPayStatus(OrderEnum.IS_PAY).setStatus(OrderEnum.IS_BPAY);

        }
        result.setOrderSn(orderSn);
        this.baseMapper.insert(order);
        //####################异步执行订单######################
        this.orderTask(order, payinfo);
        //###################################################
        return result;

    }

    @Async()
    public void orderTask(WxOrderDetail order, Map<String, String> payinfo) {
        /**
         * 保存缓存设置半小时超时设计
         */
        if (payinfo.size() > 0) {
            String cache = "XDLORDER_" + order.getOrderSn();
            cacheService.setOrderCache(cache, payinfo, 60 * 30);//60 * 30
            if (Func.isNotEmpty(order.getCouponId())) {
                //扣除优惠券
                this.backCoupon(order.getCouponId(),2);
            }
        } else {
            /**
             * 异步发送通知短信
             */
            WxActivityDto act = detailService.getActById(order.getActId());
            HashMap<String, Object> param = new HashMap<>();
            param.put("name", order.getName());
            param.put("time", DateUtil.format(order.getAppointTime(), DateUtil.PATTERN_DATE));
            param.put("activity", act.getTitle());
            param.put("address", act.getAddress());
            param.put("shop", act.getShopName());
            SMSEntity params = new SMSEntity();
            params.setPhone(order.getPhone());
            params.setSignName("新动力");
            params.setTemplateCode("SMS_241357479");
            params.setSmsParams(param);
            smsClient.sendSMS(params);
            /**
             * 发送系统信息
             */
            String msg = "%s 先生/女士：已成功预约 %s 于 %s 的 %s 活动，请关注！<a href=\"http://admin.xin-dl.com\">点击查看详情</a>";
            msg = String.format(msg,order.getName(),DateUtil.format(order.getAppointTime(), DateUtil.PATTERN_DATE), act.getShopName(), act.getTitle());
            SysAnnouncement announcement = new SysAnnouncement();
            announcement.setTitile("新订单通知！");
            announcement.setMsgContent(msg);
            announcement.setPriority("M");
            announcementService.save(announcement);
            /**
             * 发送企业微信信息
             */
            wxWorkApi.sendWxWorkOffer(msg);

        }
        //保存用户模版信息
        QueryWrapper<WxUserTemp> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(WxUserTemp::getIdCard, order.getIdCard());
        WxUserTemp userTemp = tempService.getOne(wrapper);
        if (Func.isEmpty(userTemp)) {
            WxUserTemp temp = new WxUserTemp();
            Func.copy(order, temp);
            tempService.putUser(temp);
        }
    }


    @Override
    public IPage<WxOrderDto> getOrderList(WxOrderModel model) {
        return this.baseMapper.getOrderList(new Page<>(model.getPageNo(), model.getPageSize()), model, BaseContextHandler.getUserID());
    }


    @Override
    public String cancelOrder(Long id) {
        String returnMsg = "取消订单成功！";
        WxOrderDetail wxOrderDetail = this.baseMapper.selectById(id);
        WxActivityDto act = detailService.getActById(wxOrderDetail.getActId());
        if (act == null) {
            return "活动已下线！";
        }
        if (Func.isNotEmpty(act.getNeedPay()) && act.getNeedPay()) {
            WxBPayRefundRequest refundRequest = new WxBPayRefundRequest();
            refundRequest.setOutTradeNo(wxOrderDetail.getOrderSn());
            refundRequest.setTotalFee((int) (wxOrderDetail.getPrice().doubleValue() * 100));
            refundRequest.setRefundFee((int) (wxOrderDetail.getPrice().doubleValue() * 100));
            refundRequest.setNotifyUrl(properties.getCallback() + "/wx/order/refundCallback");
            WxBPayRefundResult wxBPayRefundResult = bPay.wxRefund(refundRequest);
            returnMsg = wxBPayRefundResult.getReturnMsg();
            if (returnMsg.equals("OK")) {
                wxOrderDetail.setPayStatus(OrderEnum.REFUND).setStatus(OrderEnum.AFTER_SALE);
                this.baseMapper.updateById(wxOrderDetail);
                //退还优惠券
                this.backCoupon(wxOrderDetail.getCouponId(),1);
            }
        } else {
            wxOrderDetail.setStatus(OrderEnum.AFTER_SALE);
            this.baseMapper.updateById(wxOrderDetail);
            //退还优惠券
            //this.backCoupon(wxOrderDetail.getCouponId());
            /**
             * 发送短信提示
             */
            HashMap<String, Object> param = new HashMap<>();
            param.put("name", wxOrderDetail.getName());
            param.put("time", DateUtil.format(wxOrderDetail.getAppointTime(), DateUtil.PATTERN_DATE));
            param.put("activity", act.getTitle());
            param.put("shop", act.getShopName());
            SMSEntity params = new SMSEntity();
            params.setPhone(wxOrderDetail.getPhone());
            params.setSignName("新动力");
            params.setTemplateCode("SMS_241347432");
            params.setSmsParams(param);
            smsClient.sendSMS(params);
        }
        return returnMsg;
    }

    private void backCoupon(Long couponId,Integer status) {
        //退还优惠券
        if (Func.isNotEmpty(couponId) && couponId != -1) {
            WxOwnerCoupon wxOwnerCoupon = ownerCouponService.getById(couponId);
            wxOwnerCoupon.setStatus(status);
            ownerCouponService.updateById(wxOwnerCoupon);
        }

    }

    /**
     * 关闭订单
     *
     * @param id
     * @return
     */
    @Override
    public String closeOrder(Long id) {
        WxOrderDetail wxOrderDetail = this.baseMapper.selectById(id);
        WxBPayOrderCloseResult closeResult = bPay.closeWxOrder(wxOrderDetail.getOrderSn());
        String returnMsg = closeResult.getReturnMsg();
        if (returnMsg.equals("OK")) {
            wxOrderDetail.setPayStatus(OrderEnum.CANLE_PAY).setStatus(OrderEnum.LOST_EFFICACY);
            this.baseMapper.updateById(wxOrderDetail);
            //扣除优惠券
            this.backCoupon(wxOrderDetail.getCouponId(),1);
        }
        return returnMsg;
    }

    @Override
    public Map<Object, Object> payOrder(String orderSn) {
        String cache = "XDLORDER_" + orderSn;
        Map<Object, Object> payinfo = cacheService.getMapCache(cache);
        return payinfo;
    }


}
